<?php
/**
 * This file is part of the jdufs project
 * 
 * (c) tiglog <xq@tiglog.com>
 * 
 * For the full copyright and license information, please view the LICENSE file
 * that was distributed with this source code. 
 */
namespace tiglog\datatables;

use Yii;
use yii\base\Action;
use yii\base\InvalidConfigException;
use yii\data\ActiveDataProvider;
use yii\db\ActiveQuery;
use yii\db\ActiveRecord;
use yii\web\Response;

class DataAction extends Action
{
    /**
     * Types of request method
     */
    const REQUEST_METHOD_GET = 'GET';
    const REQUEST_METHOD_POST = 'POST';

    /**
     * @see \tiglog\datatable\DataAction::getParam
     * @var string
     */
    public $requestMethod = self::REQUEST_METHOD_GET;

    /**
     * @var BaseDt
     */
    public $dt;

    /**
     * @return array|ActiveRecord[]
     */
    public function run()
    {
        $originalQuery = $this->dt->getQuery();

        $draw = $this->getParam('draw');

        $filterQuery = clone $originalQuery;
        $filterQuery->where = null;

        $search = $this->getParam('search', ['value' => null, 'regex' => false]);

        // 排序
        $columns = $this->getParam('columns', []);
        $order = $this->getParam('order', []);
        $filterQuery = $this->applyFilter($filterQuery, $columns, $search);
        $filterQuery = $this->applyOrder($filterQuery, $columns, $order);
        if (!empty($originalQuery->where)) {
            $filterQuery->andWhere($originalQuery->where);
        }
        $filterQuery
            ->offset($this->getParam('start', 0))
            ->limit($this->getParam('length', -1));

        $countQuery = clone $filterQuery;
        Yii::$app->response->format = Response::FORMAT_JSON;
        try {
            $response = [
                'draw' => (int)$draw,
                'recordsTotal' => (int)$originalQuery->count(),
                'recordsFiltered' => (int)$countQuery->count(),
                'data' => $this->formatData($filterQuery, $columns),
            ];
        } catch (\Exception $e) {
            return ['error' => $e->getMessage()];
        }

        return $response;
    }

    /**
     * Extract param from request
     * 
     * @return mixed
     */
    protected function getParam($name, $defaultValue = null)
    {
        return $this->requestMethod == self::REQUEST_METHOD_GET ?
            Yii::$app->request->getQueryParam($name, $defaultValue) :
            Yii::$app->request->getBodyParam($name, $defaultValue);
    }

    /**
     * 搜索关键词，只能靠用户自定义
     * 
     * @param ActiveQuery $query
     * @param array $columns
     * @param array $search
     * @return ActiveQuery
     */
    public function applyFilter(ActiveQuery $query, $columns, $search)
    {
        return call_user_func([$this->dt, 'onFilter'], $query, $columns, $search);
    }

    /**
     * 排序只能排序 model 只有字段
     * 
     * @param ActiveQuery $query
     * @param array $columns
     * @param array $order
     * @return ActiveQuery
     */
    public function applyOrder(ActiveQuery $query, $columns, $order)
    {
        $fields = $this->dt->getColumns();
        foreach ($order as $key => $item) {
            if (array_key_exists('orderable', $columns[$item['column']]) && $columns[$item['column']]['orderable'] === 'false') {
                continue;
            }
            $field = $fields[$key];
            if (!$field->attribute) {
                continue;
            }
            $sort = $item['dir'] == 'desc' ? SORT_DESC : SORT_ASC;
            $query->addOrderBy([$field->attribute => $sort]);
        }
        return $query;
    }

    /**
     * @param ActiveQuery $query
     * @param array $columns
     * @return array|ActiveRecord[]
     */
    public function formatData(ActiveQuery $query, $columns)
    {
        return call_user_func([$this->dt, 'onFormatData'], $query, $columns);
    }

}


// vim:ft=php:ts=4:sts=4:sw=4:et
